package com.itchu.auth.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itchu.auth.config.JwtProperties;
import com.itchu.common.domain.Payload;
import com.itchu.common.utils.CookieUtils;
import com.itchu.common.utils.JwtUtils;
import com.itchu.system.domain.SysUser;
import org.joda.time.DateTime;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenVerifyFilter extends BasicAuthenticationFilter {

    private JwtProperties prop;

    private StringRedisTemplate redisTemplate;



    public TokenVerifyFilter(AuthenticationManager authenticationManager,JwtProperties prop, StringRedisTemplate redisTemplate){

        super(authenticationManager);
        this.prop = prop;
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String token = CookieUtils.getCookieValue(request, prop.getUser().getAuthCookieName());
        if (token == null || token == "") {
            chain.doFilter(request,response);
            return;
        }
        // 1.通过token解析出载荷信息
        Payload<SysUser> payload = null;
        // 2.解析token
        try {
            payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), SysUser.class);
        } catch (Exception e) {
            // 如果解析失败则执行下一个过滤器
            return;
        }

        // 3.判断tokenId是否在redis里面，是就返回过期或未登录异常处理
        if (redisTemplate.hasKey(payload.getId())) {
            return;
        }
        SysUser user = payload.getUserInfo();
        // 4.获取过期时间
        Date expirationTime = payload.getExpiration();
        // 5.获取刷新点时间
        DateTime refreshTime = new DateTime(expirationTime).minusMinutes(prop.getUser().getRefreshTime());
        // 6.如果当前时间是在刷新点时间的前面就创建新的token
        if (refreshTime.isBefore(System.currentTimeMillis())) {
            String newtoken = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), prop.getUser().getExpire());
            CookieUtils.newCookieBuilder()
                    .response(response)
                    .name(prop.getUser().getAuthCookieName())
                    .value(token)
                    .domain(prop.getUser().getCookieDomain())
                    .httpOnly(true)
                    .build();
        }
        //获取权限失败，会抛出异常
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
        //获取后，将Authentication写入SecurityContextHolder中供后序使用
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

    /**
     * 通过token，获取用户信息
     *
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = CookieUtils.getCookieValue(request, prop.getUser().getAuthCookieName());
        if (token != null) {
            // 1.通过token解析出载荷信息
            Payload<SysUser> payload = null;
            // 2.解析token
            try {
                payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), SysUser.class);
            } catch (Exception e) {
                // 如果解析失败则执行下一个过滤器
                return null;
            }
            SysUser user = payload.getUserInfo();
            //不为null，返回
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, user.getRoles());
            }
            return null;
        }
        return null;
    }
}
